

package com.yungu.swift.system.sys.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.base.mapper.IMapper;
import com.yungu.swift.base.model.PageVo;
import com.yungu.swift.base.model.api.ApiPageParam;
import com.yungu.swift.base.service.impl.BaseServiceImpl;
import com.yungu.swift.constants.FinanceConstant;
import com.yungu.swift.system.finance.model.dto.FinanceRewardPunishDto;
import com.yungu.swift.system.finance.model.enums.FinanceEnum;
import com.yungu.swift.system.finance.model.param.AdminAccountFlowPageParam;
import com.yungu.swift.system.finance.model.param.AdminAccountPageParam;
import com.yungu.swift.system.finance.service.FinanceRewardPunishService;
import com.yungu.swift.system.sys.dao.SysAccountPassengerMapper;
import com.yungu.swift.system.sys.dao.SysBusinessOperateLogMapper;
import com.yungu.swift.system.sys.model.dto.SysAccountPassengerDto;
import com.yungu.swift.system.sys.model.dto.SysAccountPlatformDto;
import com.yungu.swift.system.sys.model.dto.SysBusinessOperateLogDto;
import com.yungu.swift.system.sys.model.enums.SysBusinessOperateEnum;
import com.yungu.swift.system.sys.model.param.AdminPassengerAccountParam;
import com.yungu.swift.system.sys.model.vo.SysPassengerAccountFlowVo;
import com.yungu.swift.system.sys.model.vo.SysPassengerAccountVo;
import com.yungu.swift.system.sys.service.SysAccountPassengerService;
import com.yungu.swift.system.sys.service.SysAccountPlatformService;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
public class SysAccountPassengerServiceImpl extends BaseServiceImpl<SysAccountPassengerDto> implements SysAccountPassengerService {
    @Autowired
    private SysAccountPassengerMapper sysAccountPassengerMapper;
    @Autowired
    private FinanceRewardPunishService financeRewardPunishService;
    @Autowired
    private SysAccountPlatformService sysAccountPlatformService;
    @Autowired
    private SysBusinessOperateLogMapper sysBusinessOperateLogMapper;

    @Override
    protected IMapper<SysAccountPassengerDto> getMapper() {
        return sysAccountPassengerMapper;
    }

    @Override
    public ResponseData<PageVo<SysPassengerAccountVo>> queryPageVo(AdminAccountPageParam pageParam) {
        PageBounds pageBounds = new PageBounds(pageParam.getPageNum(), pageParam.getPageSize());
        PageList<SysPassengerAccountVo> pageList = sysAccountPassengerMapper.queryPageVo(pageParam, pageBounds);
        PageVo<SysPassengerAccountVo> pageVo = new PageVo(pageParam.getPageNum(), pageParam.getPageSize(),
                pageList.getPaginator().getTotalCount());
        pageVo.setItems(pageList);
        return ResponseData.buildSuccessResponse(pageVo);
    }

    @Override
    public ResponseData<List<SysPassengerAccountVo>> export(AdminAccountPageParam pageParam) {
        return ResponseData.buildSuccessResponse(sysAccountPassengerMapper.queryPageVo(pageParam));
    }

    @Override
    public ResponseData<SysPassengerAccountVo> statistics(AdminAccountPageParam pageParam) {
        return ResponseData.buildSuccessResponse(sysAccountPassengerMapper.statistics(pageParam));
    }

    @Override
    public ResponseData<PageVo<SysPassengerAccountFlowVo>> flowQueryPage(AdminAccountFlowPageParam flowPageParam) {
        PageBounds pageBounds = new PageBounds(flowPageParam.getPageNum(), flowPageParam.getPageSize());
        PageList<SysPassengerAccountFlowVo> pageList = sysAccountPassengerMapper.flowQueryPage(MapUtils.convertObjToMap(
                flowPageParam), pageBounds);
        PageVo<SysPassengerAccountFlowVo> pageVo = new PageVo(flowPageParam.getPageNum(), flowPageParam.getPageSize(),
                pageList.getPaginator().getTotalCount());
        fillDate(pageList, flowPageParam.getUuid());
        pageVo.setItems(pageList);
        return ResponseData.buildSuccessResponse(pageVo);
    }

    @Override
    public ResponseData<PageList<SysPassengerAccountFlowVo>> flowQueryPage(ApiPageParam apiPageParam) {
        Map<String, Object> paramMap = MapUtils.convertObjToMap(apiPageParam);
        paramMap.put("uuid", apiPageParam.getUserUuid());
        PageBounds pageBounds = new PageBounds(apiPageParam.getNowPage(), apiPageParam.getPageSize());
        PageList<SysPassengerAccountFlowVo> pageList = sysAccountPassengerMapper.flowQueryPage(paramMap, pageBounds);
        apiFillDate(pageList, apiPageParam.getUserUuid());
        return ResponseData.buildSuccessResponse(pageList);
    }

    @Override
    public ResponseData<List<SysPassengerAccountFlowVo>> flowExport(AdminAccountFlowPageParam flowPageParam) {
        List<SysPassengerAccountFlowVo> flowVoList = sysAccountPassengerMapper.flowQueryPage(flowPageParam);
        fillDate(flowVoList, flowPageParam.getUuid());
        return ResponseData.buildSuccessResponse(flowVoList);
    }

    /**
     * 补充数据含义
     *
     * @param list
     * @param uuid
     */
    private void apiFillDate(List<SysPassengerAccountFlowVo> list, String uuid) {
        list.stream().forEach(accountFlowVo -> {
            boolean equals = Objects.equals(accountFlowVo.getFinanceInflow(), uuid);
            accountFlowVo.setCourseDescription(FinanceEnum.getMsg(accountFlowVo.getCourse()));
            accountFlowVo.setTransactionType(equals ? "+" : "-");
        });
    }

    /**
     * 补充数据含义
     *
     * @param list
     * @param uuid
     */
    private void fillDate(List<SysPassengerAccountFlowVo> list, String uuid) {
        list.stream().forEach(accountFlowVo -> {
            accountFlowVo.setCourseDescription(FinanceEnum.getMsg(accountFlowVo.getCourse()));
            accountFlowVo.setTransactionType(Objects.equals(accountFlowVo.getFinanceInflow(), uuid) ? "收入" : "支出");
        });
    }


    @Override
    public ResponseData<SysPassengerAccountVo> findAccountPassengerVo(Map<String, Object> map) {
        return ResponseData.buildSuccessResponse(sysAccountPassengerMapper.findAccountPassengerVo(map));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseData<Boolean> adjustBalance(AdminPassengerAccountParam adjustParam) {
        //提取参数
        BigDecimal oldRechargeBalance = adjustParam.getOldRechargeBalance();
        BigDecimal oldPresentBalance = adjustParam.getOldPresentBalance();
        BigDecimal newRechargeBalance = adjustParam.getNewRechargeBalance();
        BigDecimal newPresentBalance = adjustParam.getNewPresentBalance();
        int course;
        //资金流出方,资金流入方
        String financeOutflow, financeInflow;
        //发送额
        BigDecimal amount;
        //资金流出方-期初余额
        BigDecimal startBalance;
        //资金流出方-期末余额
        BigDecimal finalBalance;
        //查询平台账户
        ResponseData<SysAccountPlatformDto> getPlatformAccount = sysAccountPlatformService.getByAppid(adjustParam.getAppid());
        if (!getPlatformAccount.isSuccess() || getPlatformAccount.getData() == null) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "查询平台账户失败！");
        }
        SysAccountPlatformDto platformAccount = getPlatformAccount.getData();
        BigDecimal cashBalance = platformAccount.getCashBalance();

        //充值余额修改
        if (newRechargeBalance != null && newRechargeBalance.compareTo(oldRechargeBalance) != 0) {
            startBalance = oldRechargeBalance;
            finalBalance = newRechargeBalance;
            //新充值余额-旧充值余额 > 0 为增加充值余额 科目为80040101 否则为减少充值余额 科目为80040102
            if (newRechargeBalance.compareTo(oldRechargeBalance) > 0) {
                course = FinanceConstant.ADD_PASSENGER_RECHARGE_BALANCE;
                //流出方-平台
                financeOutflow = platformAccount.getUuid();
                //流入方-乘客
                financeInflow = adjustParam.getUuid();
                amount = newRechargeBalance.subtract(oldRechargeBalance);
                cashBalance = cashBalance.subtract(amount);
            } else {
                course = FinanceConstant.REDUCE_PASSENGER_RECHARGE_BALANCE;
                //流出方-乘客
                financeOutflow = adjustParam.getUuid();
                //流入方-平台
                financeInflow = platformAccount.getUuid();
                amount = oldRechargeBalance.subtract(newRechargeBalance);
                cashBalance = cashBalance.add(amount);
            }
            //创建充值余额调整流水
            Boolean flag = saveSystemFinanceRewardPunish(financeOutflow, financeInflow, amount, course, startBalance,
                    finalBalance, adjustParam);
            if (!flag) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "写充值余额调整流水失败！");
            }
        }
        //赠送余额修改
        if (newPresentBalance != null && newPresentBalance.compareTo(oldPresentBalance) != 0) {
            startBalance = oldPresentBalance;
            finalBalance = newPresentBalance;
            //新赠送余额-旧赠送余额 > 0 为增加赠送余额 科目为80040201 否则为减少赠送余额 科目为80040202
            if (newPresentBalance.compareTo(oldPresentBalance) > 0) {
                course = FinanceConstant.ADD_PASSENGER_PRESENT_BALANCE;
                //流出方-平台
                financeOutflow = platformAccount.getUuid();
                //流入方-乘客
                financeInflow = adjustParam.getUuid();
                amount = newPresentBalance.subtract(oldPresentBalance);
                cashBalance = cashBalance.subtract(amount);
            } else {
                course = FinanceConstant.REDUCE_PASSENGER_PRESENT_BALANCE;
                //流出方-乘客
                financeOutflow = adjustParam.getUuid();
                //流入方-平台
                financeInflow = platformAccount.getUuid();
                amount = oldPresentBalance.subtract(newPresentBalance);
                cashBalance = cashBalance.add(amount);
            }
            //创建赠送余额调整流水
            Boolean flag = saveSystemFinanceRewardPunish(financeOutflow, financeInflow, amount, course, startBalance,
                    finalBalance, adjustParam);
            if (!flag) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "写赠送余额调整流水失败！");
            }
        }
        //修改平台账户现金余额
        platformAccount.setUpdateOn(new Date());
        platformAccount.setUpdateBy(adjustParam.getUserUuid());
        platformAccount.setCashBalance(cashBalance);
        ResponseData<Boolean> editPlatformAccount = sysAccountPlatformService.edit(platformAccount);
        if (!editPlatformAccount.isSuccess() || editPlatformAccount.getData() == null || Objects.equals(
                editPlatformAccount.getData(), Boolean.FALSE)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "修改平台账户余额失败！");
        }
        //修改乘客账户余额
        SysAccountPassengerDto accountPassengerDto = new SysAccountPassengerDto();
        accountPassengerDto.setUuid(adjustParam.getUuid());
        accountPassengerDto.setUpdateBy(adjustParam.getUserUuid());
        accountPassengerDto.setUpdateOn(new Date());
        if (null != newRechargeBalance) {
            accountPassengerDto.setRechargeBalance(newRechargeBalance);
        }
        if (null != newPresentBalance) {
            accountPassengerDto.setPresentBalance(newPresentBalance);
        }
        if (sysAccountPassengerMapper.edit(accountPassengerDto) == 0) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "调整余额失败，请重试");
        }
        if (newPresentBalance.compareTo(oldPresentBalance) != 0) {
            addLog("presentBalance", oldPresentBalance, newPresentBalance, adjustParam);
        }
        if (newRechargeBalance.compareTo(oldRechargeBalance) != 0) {
            addLog("rechargeBalance", oldRechargeBalance, newRechargeBalance, adjustParam);
        }
        return ResponseData.buildSuccessResponse("调整余额成功", Boolean.TRUE);
    }

    /**
     * 创建修改余额流水
     *
     * @param financeOutflow 资金流出方
     * @param financeInflow  资金流入方
     * @param amount         发生额
     * @param course         科目
     * @param startBalance   期初余额
     * @param finalBalance   期末余额
     */
    private Boolean saveSystemFinanceRewardPunish(String financeOutflow, String financeInflow, BigDecimal amount,
                                                  int course, BigDecimal startBalance, BigDecimal finalBalance,
                                                  AdminPassengerAccountParam adjustParam) {
        FinanceRewardPunishDto financeRewardPunishDto = new FinanceRewardPunishDto();
        financeRewardPunishDto.setUuid(StringUtils.buildUUID());
        financeRewardPunishDto.setFinanceNumber(StringUtils.buildUUID());
        financeRewardPunishDto.setFinanceOutflow(financeOutflow);
        financeRewardPunishDto.setFinanceInflow(financeInflow);
        financeRewardPunishDto.setAmount(amount);
        financeRewardPunishDto.setCourse(course);
        financeRewardPunishDto.setHappenTime(new Date());
        financeRewardPunishDto.setStartBalance(startBalance);
        financeRewardPunishDto.setFinalBalance(finalBalance);
        financeRewardPunishDto.setDescription(adjustParam.getRemark());
        financeRewardPunishDto.setCreateBy(adjustParam.getUserUuid());
        financeRewardPunishDto.setCreateOn(new Date());
        financeRewardPunishDto.setAppid(adjustParam.getAppid());
        ResponseData<Boolean> add = financeRewardPunishService.add(financeRewardPunishDto);
        if (add.isSuccess() && add.getData() != null && Objects.equals(add.getData(), Boolean.TRUE)) {
            return true;
        }
        return false;
    }

    /**
     * 插入修改日志
     */
    private void addLog(String field, Object beforeValue, Object afterValue, AdminPassengerAccountParam adjustParam) {
        try {
            SysBusinessOperateLogDto operateLogDto = new SysBusinessOperateLogDto();
            operateLogDto.setBeforeValue(String.valueOf(beforeValue));
            operateLogDto.setAfterValue(String.valueOf(afterValue));
            switch (field) {
                case "rechargeBalance":
                    operateLogDto.setOperationCode(SysBusinessOperateEnum.UDP_PASSENGER_BALANCE.getCode());
                    operateLogDto.setOperationName(SysBusinessOperateEnum.UDP_PASSENGER_BALANCE.getName());
                    operateLogDto.setOperationDescribe("客服修改乘客充值余额");
                    break;
                case "presentBalance":
                    operateLogDto.setOperationCode(SysBusinessOperateEnum.UDP_PASSENGER_BALANCE.getCode());
                    operateLogDto.setOperationName(SysBusinessOperateEnum.UDP_PASSENGER_BALANCE.getName());
                    operateLogDto.setOperationDescribe("客服修改乘客赠送余额");
                    break;
                default:
                    break;
            }
            operateLogDto.setCreateBy(adjustParam.getUserUuid());
            operateLogDto.setCreateOn(new Date());
            operateLogDto.setAgentUuid(adjustParam.getUserAgentUuid());
            operateLogDto.setCompanyUuid(adjustParam.getUserCompanyUuid());
            operateLogDto.setAppid(adjustParam.getAppid());
            operateLogDto.setUuid(StringUtils.buildUUID());
            operateLogDto.setOperationUserIp(adjustParam.getUserip());
            operateLogDto.setRemark(adjustParam.getRemark());
            sysBusinessOperateLogMapper.add(operateLogDto);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}